#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<time.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/msg.h>
#include<sys/shm.h>
#include<pthread.h>
#include<dirent.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define USER_FILE "user.txt"

struct TransFileInfo {
    unsigned long pktId; //包编号
    unsigned long fileId;  //文件编号
    char filename[128];    //文件名
    unsigned long offset;  //起始偏移位置
    unsigned long fileSize;  //文件大小
    int status;        //发送状态，0表示未开始，1表示开始
    unsigned long startTime;  //开始发送时间
    unsigned long int peerIp;  //对方IP
};

struct user_infor
{
	char pcname[40];
	char pc[40];
	char packnum[20];
	char cmd[10];
	char name[20];
	char sign[30];
	char depart[20];
	char tel[20];
	char email[30];
	char ip[30];
	char mac[30];
	struct user_infor *next;
};
typedef struct user_infor User;

struct information
{
	char name[20];
	char sign[30];
	char depart[20];
	char tel[20];
	char email[30];
	char ip[30];
	char mac[30];
	struct information *next;
};
typedef struct information Infor;

int num = 2000000;
User *head = NULL;

Infor *read_infor()
{
	FILE *fp;
	Infor *p;
	fp = fopen("value.txt","r");
	if(fp == NULL)
	{
		perror("open infor file read!\n");
		return NULL;
	}
	p = (Infor *)malloc(sizeof(Infor));
	if(NULL == p)
	{
		printf("malloc fail\n");
		fclose(fp);
		return NULL;
	}
	memset(p,0,sizeof(Infor));
	while(!feof(fp))
	{
		fscanf(fp,"%s",p->name);
		fscanf(fp,"%s",p->sign);
		fscanf(fp,"%s",p->depart);
		fscanf(fp,"%s",p->tel);
		fscanf(fp,"%s",p->email);
		fscanf(fp,"%s",p->ip);
		fscanf(fp,"%s",p->mac);
	}
	fclose(fp);
	return p;
}

int rewrite_infor(Infor *head)
{
	Infor *p;
	p = head;
	FILE *fp;
	fp = fopen("value.txt","w");
	if(fp == NULL)
	{
		printf("open error");
		return 0;
	}
	fseek(fp,0,SEEK_SET);
	while(p != NULL)
	{
		fprintf(fp,"%s\n",p->name);
		fprintf(fp,"%s\n",p->sign);
		fprintf(fp,"%s\n",p->depart);
		fprintf(fp,"%s\n",p->tel);
		fprintf(fp,"%s\n",p->email);
		fprintf(fp,"%s\n",p->ip);
		fprintf(fp,"%s\n",p->mac);
		p = p->next;
	}
	fclose(fp);
	return 0;
}

int add_user()
{
	User *pnew;
	if(head ==NULL)
	{
		pnew = (User *)malloc(sizeof(User));
		if(pnew == NULL){
			printf("malloc error");
		return 0;
		}
		strcpy(pnew->pcname,"PC");
		strcpy(pnew->pc,"ASUS");
		strcpy(pnew->packnum,"9999999");
		strcpy(pnew->cmd,"1025");
		strcpy(pnew->name,"wanglu");
		strcpy(pnew->sign,"yilushunfeng");
		strcpy(pnew->depart,"WorkGroup");
		strcpy(pnew->tel,"15252435862");
		strcpy(pnew->email,"1609116185@qq.com");
		strcpy(pnew->ip,"192.168.186.129");
		strcpy(pnew->mac,"1C-B7-2C-8D-08-74");
		pnew->next = NULL;
		head = pnew;
	}
	return 0;
}

int display_user()
{
	User *p;
	int n = 1;
	p = head;
	printf("###############################\n");
	while(p!=NULL)
	{
		printf("%-2d,Name:%-20s,Sign:%-30s,Tel:%-20s,Email:%-30s,Ip:%-30s,Mac:%-30s\n",n++,p->name,p->sign,p->tel,p->email,p->ip,p->mac);
		p = p->next;
	}
	printf("###############################\n");
	return 0;
}

int send_file(char *buf2,char *buf3)
{
	struct stat st;
	char buf[1024];
	User *p = head;
	while(p!=NULL)
	{
		if(!strcmp(p->name,buf2))
			break;
		p = p->next;
	}
	stat(buf3,&st);
	memset(buf,0,sizeof(buf));

	int sock = socket(AF_INET,SOCK_DGRAM,0);
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(2425);
	inet_pton(AF_INET,p->ip,&addr.sin_addr.s_addr);
	if(connect(sock,(struct sockaddr *)&addr,sizeof(addr)))
	{
		printf("connect error\n");
		close(sock);
		return 0;
	}
	int packsize = 0;
	num+=2;
	packsize = sprintf(buf,"%s:%u:%s:%s:2097440:%c%u:%s:%lx:0:1:%lu:%lu:%lu:%c","5.1.180210",num,"wanglu","wanglu-VirtualBox",0,num-1,buf3,st.st_size,st.st_ctime,st.st_mtime,st.st_atime,0);
	sendto(sock,buf,packsize,0,(struct sockaddr *)&addr,sizeof(addr));
	memset(buf,0,sizeof(buf));
	return 0;
}

int send_filenew(char *buf3)
{
	int ret;
	char buf[1024]={0};
	int sock = socket(AF_INET,SOCK_STREAM,0);
	struct sockaddr_in ad;
	ad.sin_family = AF_INET;
	ad.sin_port = htons(2425);
	inet_pton(AF_INET,"192.168.186.149",&ad.sin_addr.s_addr);
	int opt = 1;
	setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
	if(bind(sock,(struct sockaddr *)&ad,sizeof(ad)))
	{
		perror("bind error\n");
		close(sock);
		return -1;
	}
	listen(sock,5);
	int csock;
	struct sockaddr_in caddr;
	unsigned int len = sizeof(caddr);
	csock = accept(sock,(struct sockaddr *)&caddr,&len);
	sleep(1);

	int fd = open(buf3,O_RDONLY);
	memset(buf,0,sizeof(buf));
	if(fd == 0)
	{
		printf("open error\n");
	}

	while((ret = read(fd,buf,1024))>0)
	{
		send(csock,buf,ret,0);
	//	printf("%s\n",buf);
		memset(buf,0,sizeof(buf));
	}
	close(fd);
	close(csock);
	close(sock);
	printf("read over\n");

	return 0;
}

int send_message(char *buff)			
{
	char buf1[10];
	char buf2[20];
	char buf3[50];
	sscanf(buff,"%s %s %s",buf1,buf2,buf3);
	User *p = head;
	while(p!=NULL)
	{
		if(!strcmp(p->name,buf2))
			break;
		p = p->next;
	}

	int sock = socket(AF_INET,SOCK_DGRAM,0);

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(2425);
	inet_pton(AF_INET,p->ip,&addr.sin_addr.s_addr);

	char buf[1024];
	int packsize = 0;
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:487:%s","5.1.180210",num,"wanglu","wanglu-VirtualBox",p->mac);
	sendto(sock,buf,packsize,0,(struct sockaddr *)&addr,sizeof(addr));
	memset(buf,0,sizeof(buf));
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:288:%s[rich]0A0000000000860008AE5F6F8FC596D19E12000000000000000000000000000000000000[/rich]"
		,"5.1.180210",num,"wanglu","wanglu-VirtualBox",buf3);
	sendto(sock,buf,packsize,0,(struct sockaddr *)&addr,sizeof(addr));
	memset(buf,0,sizeof(buf));
	return 0;
}

int send_33_pack(User *pr)			
{
	User *p = head;
	while(p!=NULL)
	{
		if(!strcmp(p->pcname,pr->pcname))
			break;
		p=p->next;
	}
	if(p==NULL)
	{
		printf("leave\n");
		return 0;
	}
	int sock = socket(AF_INET,SOCK_DGRAM,0);
	int opt = 1;
	int ret;
	if((ret = setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)))!=0)
	{
		perror("setsockopt error\n");
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(2425);
	inet_pton(AF_INET,p->ip,&addr.sin_addr.s_addr);

	char buf[1024];
	int packsize = 0;
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:33:%s","5.1.180210",num,"wanglu","wanglu-VirtualBox,",pr->packnum);
	sendto(sock,buf,packsize,0,(struct sockaddr *)&addr,sizeof(addr));
	memset(buf,0,sizeof(buf));
	return 0;
}

int send_3_pack(User* pt)			
{
	int sock = socket(AF_INET,SOCK_DGRAM,0);
	int opt = 1;
	int ret;
	if((ret = setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)))!=0)
	{
		perror("setsockopt error\n");
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(2425);
	inet_pton(AF_INET,"192.168.186.255",&addr.sin_addr.s_addr);

	char buf[1024];
	int packsize = 0;
	int len = 0;
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:3:","5.1.180210",num,"wanglu","wanglu-VirtualBox");
	len = sprintf(buf+packsize,"%s%c%s%c%s%c%c%s%c%s%c%c91%c","wanglu01",0,"WorkGroup",0,"08-00-27-1F-09-CD",0,0,"15252435862",0,"1609116185@qq.com",0,0,0);
	packsize += len;
	len = sprintf(buf+packsize,"%s%c%c16%c10000001%c%s%c%s","192.168.186.149",0,0,0,0,"yilushunfeng",0,"wanglu-VirtualBox");
	packsize += len;
	sendto(sock,buf,packsize,0,(struct sockaddr *)&addr,sizeof(addr));
	memset(buf,0,sizeof(buf));
	return 0;
}

User *analysis_broadcast_pack(char *p)
{
	char *q;
	User *pr;
	pr = (User *)malloc(sizeof(User));
	pr->next =NULL;
	for(int i=0;i<5;i++)
	{
		q = strchr(p,':');
		*q = '\0';
		switch(i)
		{
			case 1://printf("0:%s\n",p);
			strcpy(pr->packnum,p);
			break;
			case 2://printf("2:%s\n",p);
			strcpy(pr->pcname,p);
			break;
			case 3://printf("3:%s\n",p);
			strcpy(pr->pc,p);
			break;
			case 4://printf("4:%s\n",p);
			strcpy(pr->cmd,p);
			break;
			default:break;
		}
		p = q+1;
	}
	//	printf("%s\n",pr->cmd);
	if(strncmp(pr->cmd,"2097440",7)!=0)
	{
		for(int i=0;i<14;i++)
		{
			q = strchr(p,'\0');
			switch(i)
			{
				case 0://printf("0:%s\n",p);
				strcpy(pr->name,p);
				break;
				case 1://printf("1:%s\n",p);
				strcpy(pr->depart,p);
				break;
				case 2://printf("2:%s\n",p);
				strcpy(pr->mac,p);
				break;
				case 4://printf("4:%s\n",p);
				strcpy(pr->tel,p);
				break;
				case 5://printf("5:%s\n",p);
				strcpy(pr->email,p);
				break;
				case 8://printf("8:%s\n",p);
				strcpy(pr->ip,p);
				break;
				case 12://printf("12:%s\n",p);
				strcpy(pr->sign,p);
				break;
				default:break;
			}
			p = q+1;
		}
	}
	else
	{
		p = p+1;
		q = strchr(p,':');
		*q = '\0';
		p = q +1;
		q = strchr(p,':');
		*q = '\0';
	//	printf("1:%s\n",p);
		strcpy(pr->name,p);
	}
	return pr;	
}

int send_96_pack(User *pr)
{
	char buf[1024];
	User *p = head;
	while(p!=NULL)
	{
		if(!strcmp(p->pcname,pr->pcname))
			break;
		p=p->next;
	}
	char s1[30],s2[30];
	int k;
	sscanf(pr->packnum,"%d",&k);
	sprintf(s1,"%x",k);
	sprintf(s2,"%x",k-1);
	int sock = socket(AF_INET,SOCK_STREAM,0);
	struct sockaddr_in ad;
	ad.sin_family = AF_INET;
	ad.sin_port = htons(2425);
	inet_pton(AF_INET,p->ip,&ad.sin_addr.s_addr);

	if(connect(sock,(struct sockaddr *)&ad,sizeof(ad)))
	{
		printf("connect error\n");
		close(sock);
		return 0;
	}

	int packsize = 0;
	int ret;
	num++;
	packsize = sprintf(buf,"%s:%u:%s:%s:96:%s:%s:0:","5.1.180210",num,"wanglu","wanglu-VirtualBox",s1,s2);
	sendto(sock,buf,packsize,0,(struct sockaddr *)&ad,sizeof(ad));
	memset(buf,0,sizeof(buf));

	int fd = open(pr->name,O_WRONLY | O_CREAT ,0666);
	sleep(1);
	while((ret = read(sock,buf,sizeof(buf)))>0)
	{
		printf("%d\n",ret);
		write(fd,buf,ret);
		memset(buf,0,sizeof(buf));
	}
	close(fd);
	printf("write over\n");
	return 0;
}

int judge_send_3_pack(User *p)
{
	User *pold;
	User *pr;
	add_user();
	pr = head;
	while(pr!=NULL)
	{
		if(strncmp(p->ip,pr->ip,15)==0)
		{
			send_3_pack(p);
			return 0;
		}
		else if(strncmp(p->ip,"192.168.186.149",15)==0)
			return 0;
		pold = pr;
		pr = pr->next;
	}
	pold->next = p;
	p->next = NULL;
	send_3_pack(p);
	return 0;
}

void *send_broadcast_pack(void *arg)
{
	int sock = socket(AF_INET,SOCK_DGRAM,0);
	int opt = 1;
	int ret;
	if((ret = setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)))!=0)
	{
		perror("setsockopt error\n");
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(2425);
	inet_pton(AF_INET,"192.168.186.255",&addr.sin_addr.s_addr);

	char buf[1024];
	while(1)
	{
		int packsize = 0;
		int len = 0;
		num++;
		packsize = sprintf(buf,"%s:%u:%s:%s:1025:","5.1.180210",num,"wanglu","wanglu-VirtualBox");
		len = sprintf(buf+packsize,"%s%c%s%c%s%c%c%s%c%s%c%c91%c","wanglu01",0,"WorkGroup",0,"08-00-27-1F-09-CD",0,0,"15252435862",0,"1609116185@qq.com",0,0,0);
		packsize += len;
		len = sprintf(buf+packsize,"%s%c%c16%c10000001%c%s%c%s","192.168.186.149",0,0,0,0,"yilushunfeng",0,"wanglu-VirtualBox");
		packsize += len;

		sendto(sock,buf,packsize,0,(struct sockaddr *)&addr,sizeof(addr));
		memset(buf,0,sizeof(buf));
		sleep(5);
	}
	close(sock);
}

void *recv_broadcast_pack(void *arg)
{
	int sock = socket(AF_INET,SOCK_DGRAM,0);
	int opt = 1;
	int ret;
	User *p;
	if((ret = setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&opt,sizeof(opt)))!=0)
	{
		perror("setsockopt error\n");
	}
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(2425);
	addr.sin_addr.s_addr = INADDR_ANY;
	
	setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
	if(bind(sock,(struct sockaddr *)&addr,sizeof(addr)))
	{
		perror("bind error\n");
		close(sock);
		return NULL;
	}
	char buf[1024]={0};
	struct sockaddr_in ad;
	char *q;
	unsigned int len = sizeof(ad);
	while((ret = recvfrom(sock,buf,sizeof(buf),0,(struct sockaddr *)&ad,&len))>0)
	{
		/*for(int i=0;i<ret;i++)
		{
			printf("%c",buf[i]);
		}
		printf("%s\n",buf);*/
		p = analysis_broadcast_pack(buf);
		if(!strncmp(p->cmd,"1025",4))
			judge_send_3_pack(p);
		else if(!strncmp(p->cmd,"487",3))
			send_33_pack(p);
		else if(!strncmp(p->cmd,"288",3))
		{
			q = strchr(p->name,'[');
			*q = '\0';
			printf("%s\n",p->name);
			send_33_pack(p);
		}
		else if(!strncmp(p->cmd,"2097440",7))
		{
			send_33_pack(p);
			send_96_pack(p);
		}
		memset(buf,0,sizeof(buf));
	}
	return NULL;
}

void deal(char *s)
{
	Infor *p = read_infor();
	char *s1,*s2;
	char buf1[10];
	char buf2[20];
	char buf3[20];
	//display_infor(p);
	if(!strcmp(s,"get name"))
		printf("%s\n",p->name);
	else if(!strcmp(s,"get sign"))
		printf("%s\n",p->sign);
	else if(!strcmp(s,"get depart"))
		printf("%s\n",p->depart);
	else if(!strcmp(s,"get tel"))
		printf("%s\n",p->tel);
	else if(!strcmp(s,"get email"))
		printf("%s\n",p->email);
	else if(!strcmp(s,"get ip"))
		printf("%s\n",p->ip);
	else if(!strcmp(s,"get mac"))
		printf("%s\n",p->mac);
	else if(!strcmp(s,"list"))
		display_user();
	else if(!strcmp(s,"free"))
		free(head);
	else if(!strncmp(s,"sendto",6))
		send_message(s);
	else if(!strncmp(s,"sendfile",8))
	{
		sscanf(s,"%s %s %s",buf1,buf2,buf3);
		send_file(buf2,buf3);
		send_filenew(buf3);
	}
	else if(!strncmp(s,"set name",8))
	{
		s1 = s + 9;
		s2 = p->name + 5;
		strcpy(s2,s1);
		printf("%s\n",p->name);
		rewrite_infor(p);	
	}
}

int main()
{
	char buf[30] = {0};
	pthread_t a_tid;
	pthread_t b_tid;
	pthread_create(&a_tid,NULL,send_broadcast_pack,NULL);
	pthread_create(&b_tid,NULL,recv_broadcast_pack,NULL);
	while(1)
	{
		printf("wanglu#");
		gets(buf);
		if(!strcmp(buf,"quit"))
			return 0;
		deal(buf);
		memset(buf,0,sizeof(buf));
	}
	return 0;
}